package avicit.bdp.dgs.qa.service.algo.raw.data.pcm.utils;

import avicit.bdp.dgs.qa.service.algo.raw.data.pcm.entity.PcmHeadInfo;
import avicit.bdp.dgs.qa.service.algo.raw.data.pcm.entity.PcmParamInfo;
import avicit.bdp.dgs.qa.service.algo.raw.data.pcm.entity.PcmTime;

import java.io.IOException;

/**
 * @金航数码科技有限责任公司
 * @作者：developer
 * @邮箱：developer@avic-digital.com
 * @创建时间： 2023-11-01
 * @类说明：FrameUtils
 * @修改记录：
 * @注意事项：
 * @主要功能：数据格式转换
 */
public class FrameUtils {
    private int sync_len;
    private byte[] sync_byte;
    private short[] sync_short;
    private int sync_position;
    private int position;
    private int id_diff;
    private int word_length;
    private int sub_frame_deepth;
    private PcmParamInfo hourParam;
    private PcmParamInfo minuteParam;
    private PcmParamInfo secondParam;
    private PcmParamInfo microSecondParam;
    private int frame_length;
    private int total_frame_length;

    public FrameUtils(PcmHeadInfo headInfo) {
        sync_len = headInfo.getStreamInfoList().get(0).getSync_word_length() / 16; // 同步字字数
        sub_frame_deepth = headInfo.getStreamInfoList().get(0).getSubframe_deepth();
        String sync_str = headInfo.getStreamInfoList().get(0).getSync_pattern()
                .replace("0x", "").replace("0X", "").trim();
        sync_byte = DataConvertUtils.hexToByte(sync_str);
        sync_short = new short[sync_len];
        frame_length = headInfo.getStreamInfoList().get(0).frame_length;
        total_frame_length = sub_frame_deepth * frame_length;
        for (int i = 0; i < sync_byte.length; i += 2) {
            sync_short[i / 2] = DataConvertUtils.byte2short(new byte[]{sync_byte[i + 1], sync_byte[i]});
        }

        int id_diff = headInfo.getStreamInfoList().get(0).getId_position() - sync_len;
        word_length = headInfo.getStreamInfoList().get(0).getWord_length();
        int stream_no = 0 + 1;
        for (PcmParamInfo param : headInfo.getStreamInfoList().get(0).getParams()) {
            // 取子帧中的时间
            if (param.getName().trim().equalsIgnoreCase("HOUR_" + stream_no)) {
                this.hourParam = param;
            } else if (param.getName().trim().equalsIgnoreCase("MINUTE_" + stream_no)) {
                this.minuteParam = param;
            } else if (param.getName().trim().equalsIgnoreCase("SECOND_" + stream_no)) {
                this.secondParam = param;
            } else if (param.getName().trim().equalsIgnoreCase(stream_no + "TOP_" + stream_no)) {
                this.secondParam = param;
            }
        }
    }

    public byte[] findFirstFrame(DataFileUtils dfu) throws IOException {
        int len = 0;
        int id_value = -1;
        byte[] word_bytes = new byte[sync_len];
        while ((len = dfu.readBytes(word_bytes)) != -1) {
            boolean result = dfu.checkIsSync(sync_short, 0, word_bytes);
            if (result) {
                break;
            }
        }

        int temp_id_diff = id_diff;
        while (temp_id_diff > 0) {
            if ((len = dfu.readBytes(word_bytes)) != -1) {
                id_value = DataConvertUtils.byte2short(word_bytes);
            }
            temp_id_diff--;
        }

        dfu.readBytes(word_bytes);
        id_value = DataConvertUtils.byte2short(word_bytes);
        // 判断是否为0，代表全帧开始
        if (id_value != 0) {
            dfu.skip(((sub_frame_deepth - id_value) * this.frame_length * 2) - 2);
            if ((len = dfu.readBytes(word_bytes)) != -1) {
                id_value = DataConvertUtils.byte2short(word_bytes);
            }
        }

        // 返回第一个全帧
        byte[] frame_bytes = new byte[(this.frame_length * this.sub_frame_deepth * 2) - sync_byte.length - word_bytes.length];
        if ((len = dfu.readBytes(frame_bytes)) != -1) {
            return frame_bytes;
        } else {
            return null;
        }
    }

    public int getFrame(DataFileUtils dfu, byte[] frame_bytes) throws IOException {
        return dfu.readBytes(frame_bytes);
    }

    public boolean checkSyncWord(byte[] word_bytes) {
        for (int i = 0; i < word_bytes.length; i += 2) {
            if (sync_short[i / 2] != DataConvertUtils.byte2short(new byte[]{word_bytes[i], word_bytes[i + 1]})) {
                return false;
            }
        }

        return true;
    }

    public PcmTime getFrameDate(byte[] frame_bytes) {
        int hour_frame_no = hourParam.getFrame_no()[0];
        int minute_frame_no = minuteParam.getFrame_no()[0];
        int second_frame_no = secondParam.getFrame_no()[0];

        int hour_word_no = hourParam.getWord_no()[0];
        int minute_word_no = minuteParam.getWord_no()[0];
        int second_word_no = secondParam.getWord_no()[0];

        // 去全帧中获取
        int hour_position = (hour_frame_no * frame_length + hour_word_no) * (word_length / 8);
        int minute_position = (minute_frame_no * frame_length + minute_word_no) * (word_length / 8);
        int second_position = (second_frame_no * frame_length + second_word_no) * (word_length / 8);

        byte[] hour_bytes = new byte[]{frame_bytes[hour_position], frame_bytes[hour_position + 1]};
        byte[] minute_bytes = new byte[]{frame_bytes[minute_position], frame_bytes[minute_position + 1]};
        byte[] second_bytes = new byte[]{frame_bytes[second_position], frame_bytes[second_position + 1]};

        short hour_value = DataConvertUtils.byte2short(hour_bytes);
        short minute_value = DataConvertUtils.byte2short(minute_bytes);
        short second_value = DataConvertUtils.byte2short(second_bytes);

        int hour = ((hour_value & 0x1800) >> 11) * 10 + ((hour_value & 0x0780) >> 7);
        int minute = ((hour_value & 0x0070) >> 4) * 10 + (hour_value & 0x000F);
        int second = ((minute_value & 0xF000) >> 12) * 10 + ((minute_value & 0x0F00) >> 8);
        int micro_second = ((minute_value & 0x00F0) >> 4) * 100 + (minute_value & 0x000F) * 10 + ((second_value & 0xF000) >> 12);

        return new PcmTime(hour, minute, second, micro_second);
    }

    public PcmTime getFirstFrameDate(byte[] frame_bytes) {
        int hour_frame_no = hourParam.getFrame_no()[0];
        int minute_frame_no = minuteParam.getFrame_no()[0];
        int second_frame_no = secondParam.getFrame_no()[0];

        int hour_word_no = hourParam.getWord_no()[0];
        int minute_word_no = minuteParam.getWord_no()[0];
        int second_word_no = secondParam.getWord_no()[0];

        // 去全帧中获取
        int hour_position = (hour_frame_no * frame_length + (hour_word_no - 4)) * (word_length / 8);
        int minute_position = (minute_frame_no * frame_length + (minute_word_no - 4)) * (word_length / 8);
        int second_position = (second_frame_no * frame_length + (second_word_no - 4)) * (word_length / 8);

        byte[] hour_bytes = new byte[]{frame_bytes[hour_position], frame_bytes[hour_position + 1]};
        byte[] minute_bytes = new byte[]{frame_bytes[minute_position], frame_bytes[minute_position + 1]};
        byte[] second_bytes = new byte[]{frame_bytes[second_position], frame_bytes[second_position + 1]};

        int hour_value = DataConvertUtils.byte2short(hour_bytes);
        int minute_value = DataConvertUtils.byte2short(minute_bytes);
        int second_value = DataConvertUtils.byte2short(second_bytes);

        int hour = ((hour_value & 0x1800) >> 11) * 10 + ((hour_value & 0x0780) >> 7);
        int minute = ((minute_value & 0x0070) >> 4) * 10 + (minute_value & 0x000F);
        int second = ((second_value & 0xF000) >> 12) * 10 + ((second_value & 0x0F00) >> 8);
        int micro_second = ((minute_value & 0x00F0) >> 4) * 100 + (minute_value & 0x000F) * 10 + ((second_value & 0xF000) >> 12);

        return new PcmTime(hour, minute, second, micro_second);
    }

    public double[] readFirstFrameParamData(byte[] frame_bytes, PcmParamInfo paramInfo) {
        int[] values = new int[paramInfo.getRate()];
        double[] d_values = new double[paramInfo.getRate()];
        for (int i = 0; i < paramInfo.rate; i++) {
            // 完成拼字
            byte[] data_bytes = new byte[paramInfo.getPcm_words() * 2];
            // 根据字长去拿数据
            int index = paramInfo.getPcm_words() * 2 - 1;
            for (int j = 0; j < paramInfo.getPcm_words(); j++) {
                int sub_frame_no = paramInfo.getFrame_no()[j];
                int word_no = paramInfo.getWord_no()[j];
                int position = (sub_frame_no * frame_length + word_no + (total_frame_length / paramInfo.rate) * i)
                        * (word_length / 8)
                        - 6;
                int temp = DataConvertUtils.byte2short(new byte[]{frame_bytes[position], frame_bytes[position + 1]});
                temp = (temp >> paramInfo.getSource_bit()[j]) & DataConvertUtils.getNums(paramInfo.getBit_length()[j]);
                byte[] shink = DataConvertUtils.intToByteArray(temp);
                data_bytes[index - 1] = shink[2];
                data_bytes[index] = shink[3];
                index -= 2;
            }
            // 获得参数data_bytes，根据类型去算数据
            if (paramInfo.getPcm_words() == 1) {
                values[i] = DataConvertUtils.byte2short(data_bytes);
            } else {
                values[i] = DataConvertUtils.byteArrayToInt(data_bytes);
            }
            // 根据值进行运算
            if (paramInfo.getCal_type().trim().equalsIgnoreCase("poly")) {
                if (paramInfo.getCode_type().equalsIgnoreCase("usint")) {
                    long valueL = DataConvertUtils.getUnsigned(values[i]);
                    d_values[i] = ComputeUtils.poly_number(paramInfo.coefficient, valueL);
                } else {
                    d_values[i] = ComputeUtils.poly_number(paramInfo.coefficient, values[i]);
                }
            } else if (paramInfo.getCal_type().trim().equalsIgnoreCase("d")) {
                if (paramInfo.getCode_type().trim().equalsIgnoreCase("usint")) {
                    long valueL = DataConvertUtils.getUnsigned(values[i]);
                    d_values[i] = ComputeUtils.d_number(valueL);
                } else {
                    d_values[i] = ComputeUtils.d_number(values[i]);
                }
            } else if (paramInfo.getCal_type().trim().equalsIgnoreCase("segm")) {
                if (paramInfo.getCode_type().trim().equalsIgnoreCase("usint")) {
                    long valueL = DataConvertUtils.getUnsigned(values[i]);
                    d_values[i] = ComputeUtils.getSegemValue(valueL, paramInfo.segment_coefficients);
                } else {
                    d_values[i] = ComputeUtils.getSegemValue(values[i], paramInfo.segment_coefficients);
                }
            }
        }

        return d_values;
    }

    public double[] readParamData(byte[] frame_bytes, PcmParamInfo paramInfo) {
        int[] values = new int[paramInfo.getRate()];
        double[] d_values = new double[paramInfo.getRate()];
        for (int i = 0; i < paramInfo.rate; i++) {
            // 完成拼字
            byte[] data_bytes = new byte[paramInfo.getPcm_words() * 2];
            int index = paramInfo.getPcm_words() * 2 - 1;
            // 根据字长去拿数据
            for (int j = 0; j < paramInfo.getPcm_words(); j++) {
                int sub_frame_no = paramInfo.getFrame_no()[j];
                int word_no = paramInfo.getWord_no()[j];
                int position = (sub_frame_no * frame_length + word_no + (total_frame_length / paramInfo.rate) * i) * (word_length / 8);
                int temp = DataConvertUtils.byte2short(new byte[]{frame_bytes[position], frame_bytes[position + 1]});
                temp = (temp >> paramInfo.getSource_bit()[j]) & DataConvertUtils.getNums(paramInfo.getBit_length()[j]);
                byte[] shink = DataConvertUtils.intToByteArray(temp);
                data_bytes[index - 1] = shink[2];
                data_bytes[index] = shink[3];
                index -= 2;
            }
            // 获得参数data_bytes，根据类型去算数据
            if (paramInfo.getPcm_words() == 1) {
                values[i] = DataConvertUtils.byte2short(data_bytes);
            } else {
                values[i] = DataConvertUtils.byteArrayToInt(data_bytes);
            }
            // 根据值进行运算
            if (paramInfo.getCal_type().trim().equalsIgnoreCase("poly")) {
                if (paramInfo.getCode_type().equalsIgnoreCase("usint")) {
                    long valueL = DataConvertUtils.getUnsigned(values[i]);
                    d_values[i] = ComputeUtils.poly_number(paramInfo.coefficient, valueL);
                } else {
                    d_values[i] = ComputeUtils.poly_number(paramInfo.coefficient, values[i]);
                }
            } else if (paramInfo.getCal_type().trim().equalsIgnoreCase("d")) {
                if (paramInfo.getCode_type().trim().equalsIgnoreCase("usint")) {
                    long valueL = DataConvertUtils.getUnsigned(values[i]);
                    d_values[i] = ComputeUtils.d_number(valueL);
                } else {
                    d_values[i] = ComputeUtils.d_number(values[i]);
                }
            } else if (paramInfo.getCal_type().trim().equalsIgnoreCase("segm")) {
                if (paramInfo.getCode_type().trim().equalsIgnoreCase("usint")) {
                    long valueL = DataConvertUtils.getUnsigned(values[i]);
                    d_values[i] = ComputeUtils.getSegemValue(valueL, paramInfo.segment_coefficients);
                } else {
                    d_values[i] = ComputeUtils.getSegemValue(values[i], paramInfo.segment_coefficients);
                }
            }
        }

        return d_values;
    }
}
